﻿#include "GameCore.h"


UINT64 g_TLMyPc = 0;
UINT64 g_TLMap = 0;
UINT64 g_TLCodex = 0;
UINT64 g_TLTableMaster = 0;
UINT64 g_TLSkillQuickSlotObjectGroupActive = 0;
UINT64 g_TLInventory = 0;
UINT64 g_SpringArmComp = 0;
UINT64 g_TLTargetHelper = 0;
UINT64 g_TLServerManager = 0;
UINT64 g_TLSkillFormula = 0;
UINT64 g_TLTerritoryFog = 0;
UINT64 g_TLSkillSet = 0;
UINT64 g_TTLCalendar = 0;
UINT64 g_TLTimeTable = 0;
UINT64 g_TLEquip = 0;
UINT64 g_TLGameModeController = 0;
UINT64 g_TLParty = 0;
UINT64 g_TLMapIcon = 0;


void GameCore_GetNameUE(unsigned int id, std::string& out)
{
	if (id)
	{
		UINT32  Value_high = HIWORD(id);
		UINT16 Value = (UINT16)id;
		UINT64 FNamePool = (UINT64)(UName_BASE + GameCore_GetGameBaseAddress());

		//???????????????
		UINT64 strBegin = GameCore_read<UINT64>(FNamePool + (UINT64)Value_high * 8 + 0x10);
		if (!strBegin)
		{
			return;
		}

		strBegin = strBegin + (UINT64)Value * 2;
		UINT32 plen = GameCore_read<UINT16>(strBegin) >> 6;

		strBegin += 2;
		//DEBUG_INFO_OUTPUT("fs:GameCore_GetNameUE id:%x strBegin : %llx  len:%x", id, strBegin , plen);

		if (plen > 0)
		{
			out.assign(plen, 0);
			GameCore_read(strBegin, (void*)out.c_str(), plen);
		}

	}
}
typedef float* (__fastcall* fnGETOBJPOINT)(UINT64 obj);
bool GameCore_GetObjPoint(size_t obj, TLPoint* v)
{
	if (!IsReadPtr(obj))
	{
		return false;
	}
	auto CALL = (fnGETOBJPOINT)(GameCore_GetGameBaseAddress() + getObjPoint_CALL);
	auto result = CALL(obj);
	if (result)
	{
		memcpy(v, result, sizeof(float) * 3);
		return true;
	}
	return false;
}

void GameCore_UENameToObj(const std::string& name, bool isPrint, std::vector<UINT64>& out)
{
	UINT64 arraybegin = GameCore_read<UINT64>(GameCore_GetGameBaseAddress() + GUObjectArray_BASE);

	int count = GameCore_read<int>(GameCore_GetGameBaseAddress() + GUObjectArray_BASE + 0x14);
	for (int index = 0; index < count; index++)
	{
		UINT64 node = (GameCore_read<UINT64>(8i64 * (index / 0x10000) + arraybegin) + 0x18i64 * (index % 0x10000));
		if (node)
		{
			UINT64 obj = GameCore_read<UINT64>(node);
			if (obj)
			{
				UINT32 nameID_ = GameCore_read<UINT32>(obj + 0x18);

				//?obj+0x20?????????????????
				std::string linkName;
				GameCore_GetNameUE(nameID_, linkName);

				UINT64 parent = GameCore_read<UINT64>(obj + 0x20);;
				//PrintA("fs: ==================obj %llx", obj);

				while (parent)
				{
					//PrintA("fs:			parent %llx" , parent);
					nameID_ = GameCore_read<UINT32>(parent + 0x18);
					std::string tempName;
					GameCore_GetNameUE(nameID_, tempName);
					linkName = tempName + "." + linkName;
					parent = GameCore_read<UINT64>(parent + 0x20);
				}

				if (isPrint)
				{
					DEBUG_INFO_OUTPUT("fs:GameCore_UENameToObj %llx | %s", obj, linkName.c_str());
				}

				if (linkName == name)
				{
					DEBUG_INFO_OUTPUT("fs:GameCore_UENameToObj %llx | %s", obj, linkName.c_str());
					out.push_back(obj);
					return;
				}
			}
		}
	}
}


typedef CUEString* (__fastcall* UEGetText_FUN)(UINT64 nameObj);

bool GameCore_UEGetText(UINT64 nameObj, std::wstring& output)
{
	UINT64 vt = GameCore_read<UINT64>(nameObj);
	if (!nameObj || !vt)
	{
		return false;
	}

	UINT64 vfun = GameCore_read<UINT64>(vt + 0x10);

	if (!vfun)
	{
		return false;
	}


	auto call = (UEGetText_FUN)vfun;
	CUEString* nameStruct = call(nameObj);


	if (nameStruct && nameStruct->str && nameStruct->len && nameStruct->len < 0xfff)
	{
		//DEBUG_INFO_OUTPUT("fs:GameCore_UEGetText nameObj:%llx namePtr %p %d %ws\n", nameObj ,nameStruct.str , nameStruct.len , nameStruct.str);
		output.assign(nameStruct->str, nameStruct->len - 1);
		return true;
	}

	return false;
}

void GameCore_PointVToR(TLPoint* v)
{
	float vToR[2] = { GameCore_read<float>(GameCore_GetGameBaseAddress() + pointVToR_BASE) , GameCore_read<float>(GameCore_GetGameBaseAddress() + pointVToR_BASE + 0x4) };
	v->x = v->x + vToR[0];
	v->z = v->z;
	v->y = v->y + vToR[1];
}

void GameCore_PointRToV(TLPoint* r)
{
	float vToR[2] = { GameCore_read<float>(GameCore_GetGameBaseAddress() + pointVToR_BASE) , GameCore_read<float>(GameCore_GetGameBaseAddress() + pointVToR_BASE + 0x4) };
	r->x = r->x - vToR[0];
	r->z = r->z;
	r->y = r->y - vToR[1];
}

void UtilUTF8ToUnicode(const std::string& utf8Str, std::wstring& outWstr) {
	// 计算所需的宽字符缓冲区大小，包括结尾的 \0  
	int wstrLengthWithNull = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0);
	if (wstrLengthWithNull > 0) {
		// 实际的字符数不包括结尾的 \0  
		int wstrLength = wstrLengthWithNull - 1;
		// 分配缓冲区  
		outWstr.resize(wstrLength);
		// 执行转换  
		MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &outWstr[0], wstrLengthWithNull);
		// 此时 outWstr 的最后一个字符是 \0，但由于我们不需要它，我们不需要做额外操作  
		// 因为我们已经在 resize 时排除了这个 \0  
	}
	else {
		// 处理错误情况  
		outWstr.clear(); // 清空输出字符串  
	}
}


typedef UINT64(__fastcall* IsSkillCooldown_FUN)(UINT64 a1, UINT64 AttributeObjPtr);
bool GameCore_IsSkillCooldown(UINT64 AttributeObjPtr)
{
	UINT64 a1 = GameCore_read<UINT64, 2>(g_TLMyPc, { 0x8 , fs_skillCooldownOffset });
	if (!a1)
	{
		return false;
	}
	a1 = a1 + fs_skillCooldownOffset1;


	auto CALL = (IsSkillCooldown_FUN)(GameCore_GetGameBaseAddress() + fs_skillCooldown_CALL);
	auto result = CALL(a1, AttributeObjPtr);


	if (result)
	{
		return true;
	}


	return false;
}


typedef bool(__fastcall* fnIsObjectAttackable)(__int64 obj);

bool GameCore_IsObjectAttackable(UINT64 obj)
{
	if (!IsReadPtr(obj))
	{
		return false;
	}
	auto CALL = (fnIsObjectAttackable)(GameCore_GetGameBaseAddress() + objIsAttack_CALL);
	return CALL(obj);
}


//?ж??????????

/**
 * @brief ?????????
 *
 * ?ú????????Щ?????????????????????
 *
 * @param monsterObj:		???????
 * @param visual:			1??ж????????0????ж??
 * @return true ????????????true??
 */
typedef bool(__fastcall* isMonsterAlive_FUN)(__int64 monsterObj, char visual);

bool GameCore_IsObjectAlive(UINT64 obj)
{
	if (!IsReadPtr(obj))
	{
		return false;
	}
	auto CALL = (isMonsterAlive_FUN)(GameCore_GetGameBaseAddress() + isMonsterOptional_CALL);
	return CALL(obj, 0);
}

typedef UINT64(__fastcall* ItemToNameObjFUN)(UINT64 FieldObj);

UINT64 GameCore_ItemToNameObj(UINT64 FieldObj)
{
	switch (GameCore_read<UINT32>(FieldObj + itemTextObj_offset))
	{
	case 1:
	{
		return GameCore_read<UINT64>(FieldObj + itemTextObj_offset + 0x4);
	}
	case 2:
	{
		return GameCore_read<UINT64>(FieldObj + itemTextObj_offset + 0xc);
	}
	case 3:
	{
		return GameCore_read<UINT64>(FieldObj + itemTextObj_offset + 0x14);
	}
	default:
		break;
	}

	return 0;
}

//TaskGetIDToText

typedef UINT64(__fastcall* fnTaskGetIDToText)(UINT64 rcx, UINT64 textID);

void GameCore_TaskGetIDToText(UINT64 textID, std::wstring& text)
{
	if (!textID)
	{
		return;
	}
	auto rcx = GameCore_read<UINT64, 2>(g_TLTableMaster, { TaskGetIDToTextRCXOffset , 0x8 });
	//DEBUG_INFO_OUTPUT("fs: GameCore_TaskGetIDToText ctx.rcx %p  textID:%llx\n", ctx.rcx , textID);

	if (rcx == 0)
	{
		return;
	}

	auto CALL = (fnTaskGetIDToText)(GameCore_GetGameBaseAddress() + TaskGetIDToTextCALL);
	auto result = CALL(rcx, textID);

	if (result)
	{
		//DEBUG_INFO_OUTPUT("fs:GameCore_TaskGetIDToText result %p \n", *((UINT64*)result));

		UINT64 nameObj = GameCore_read<UINT64>(*((UINT64*)result) + 0x8);
		if (nameObj)
		{
			GameCore_UEGetText(nameObj, text);
		}
	}
	return;
}

void GameUtil_TaskDescribeFormatString(const std::wstring& input, const std::vector<std::wstring>& args, std::wstring& output)
{
	output.clear();
	size_t len = input.size();

	for (size_t i = 0; i < len; ++i) {
		if (input[i] == L'{' && i + 1 < len && isdigit(input[i + 1])) {
			size_t j = i + 1;
			while (j < len && isdigit(input[j])) {
				++j;
			}
			if (j < len && input[j] == L'}') {
				int index = std::stoi(input.substr(i + 1, j - i - 1));
				if (index < args.size()) {
					output += args[index];
					i = j;
				}
				else {
					output += L"{" + std::to_wstring(index) + L"}";
					i = j;
				}
			}
			else {
				output += input[i];
			}
		}
		else {
			output += input[i];
		}
	}
}

void GameCore_DescriptionTextFormatting(UINT64 arrayNode, std::wstring& DescribeText)
{
	std::wstring format;
	UINT64 temp = GameCore_read<UINT64>(arrayNode + SExecutionTextOFF);
	if (temp)
	{
		temp = GameCore_read<UINT64>(temp + 0x18);
		if (temp)
		{
			GameCore_UEGetText(temp, format);
		}
	}

	if (format.empty())
	{
		//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting, format empty\n");
		return;
	}



	UINT64 argumentsBegin = GameCore_read<UINT64, 2>(arrayNode, { SExecutionTextOFF , 0x50 });
	UINT32 argumentsSize = GameCore_read<UINT32, 2>(arrayNode, { SExecutionTextOFF , 0x58 });
	std::vector<std::wstring> args;

	if (argumentsBegin && argumentsSize < 0xff)
	{
		for (UINT32 i = 0; i < argumentsSize; i++)
		{
			UINT64 node = argumentsBegin + i * 0x10;
			std::wstring ParameterName;
			UINT32 id = GameCore_read<UINT32>(node + 0x8);
			if (id)
			{
				GameCore_TaskGetIDToText(id, ParameterName);
				//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting ParameterName:%ws argumentsSize:%d i:%d\n" , ParameterName.c_str() , argumentsSize , i);
				args.push_back(ParameterName);
			}

		}
	}
	//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting args size:%d\n" , args.size());
	if (!args.empty())
	{
		//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting DescriptionTextFormatting() -> args err\n");
		GameUtil_TaskDescribeFormatString(format, args, DescribeText);
		return;
	}

	DescribeText = format;

	//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting format:%ws\n" , format.c_str());
	//DEBUG_INFO_OUTPUT("fs: GameCore_DescriptionTextFormatting DescribeText:%ws\n", DescribeText.c_str());

}

void GameCore_DelegateDescriptionTextFormatting(UINT64 jinduObj, std::wstring& DescribeText)
{
	std::wstring format;
	UINT64 nameObj = GameCore_read<UINT64>(jinduObj + 0x58);
	if (nameObj)
	{
		GameCore_UEGetText(nameObj, format);
	}

	//DEBUG_INFO_OUTPUT("fs: GameCore_DelegateDescriptionTextFormatting Dformat ?? %ws \n" , format.c_str());
	UINT64 argumentsBegin = GameCore_read<UINT64>(jinduObj + 0x70);
	UINT32 argumentsSize = GameCore_read<UINT32>(jinduObj + 0x78);
	std::vector<std::wstring> args;
	if (!argumentsBegin)
	{
		return;
	}
	for (UINT64 i = 0; i < argumentsSize; i++)
	{
		UINT64 node = argumentsBegin + i * 0x10;
		std::wstring ParameterName;
		GameCore_TaskGetIDToText(GameCore_read<UINT32>(node + 0x8), ParameterName);
		//DEBUG_INFO_OUTPUT("fs: GameCore_DelegateDescriptionTextFormatting ParameterName:%ws argumentsSize:%d i:%d \n" , ParameterName.c_str() , argumentsSize , i);
		args.push_back(ParameterName);
	}
	//DEBUG_INFO_OUTPUT("fs: GameCore_DelegateDescriptionTextFormatting args size:%d \n" , args.size());
	if (!args.empty())
	{
		//DEBUG_INFO_OUTPUT("fs: GameCore_DelegateDescriptionTextFormatting DescriptionTextFormatting() -> args err\n");
		GameUtil_TaskDescribeFormatString(format, args, DescribeText);
		return;
	}

	DescribeText = format;

}

//??????????
typedef bool(__fastcall* TaskIsCompleteFUN)(UINT64 TLCodex, UINT64 id);

bool GameCore_TaskIsComplete(UINT64 ExecutionID)
{
	auto CALL = (TaskIsCompleteFUN)(GameCore_GetGameBaseAddress() + fs_taskIsComplete_CALL);
	return  CALL(g_TLCodex, ExecutionID);
}

typedef UINT64(__fastcall* DelegateTaskGetStruct_fun)(UINT64 a1, UINT64 taskID);

UINT64 GameCore_DelegateTaskGetStruct(UINT64 taskID)
{
	UINT64 a1 = GameCore_read<UINT64>(g_TLTableMaster + DelegateTaskGetStructOFF);
	if (!a1)
	{
		return 0;
	}

	auto CALL = (DelegateTaskGetStruct_fun)(GameCore_GetGameBaseAddress() + DelegateTaskGetStructCALL);
	return CALL(a1, taskID);
}

int GameCore_SendPacket(short id, void* buf, __int64 len)
{
	//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket\n");
	//????ж???????????(WorldServer)???????????(GateServer)
	UINT64 severObj = 0;
	if (GameCore_read<UINT64, 3>(g_TLServerManager + gameSocketoff_GateServer, { 0 , 0xa0 , 0xe8 }))
	{
		severObj = GameCore_read<UINT64>(g_TLServerManager + gameSocketoff_GateServer);
	}
	else if (GameCore_read<UINT64, 3>(g_TLServerManager + gameSocketoff_WorldServer, { 0 , 0xa0 , 0xe8 }))
	{
		severObj = GameCore_read<UINT64>(g_TLServerManager + gameSocketoff_WorldServer);

	}
	//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket 2\n");
	if (severObj)
	{
		//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket 3\n");
		UINT64 s = GameCore_read<UINT64, 3>(severObj, { 0xa0 , 0xe8 , 0x28 });
		if (!s)
		{
			return 0;
		}
		//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket 4\n");
		UINT64 sendBufferLen = len + 0x6;
		int ret = 0;

		//FIXED: std::shared_ptr is not necessary here
		//std::shared_ptr<char[]> oldBuf(new char[sendBufferLen], std::default_delete<char[]>());
		char* oldBuf = new char[sendBufferLen];
		*((int*)oldBuf) = sendBufferLen;
		*((short*)oldBuf + 0x2) = id;
		memcpy_s(oldBuf + 0x6, len, buf, len);
		//?ж???????????
		if (GameCore_read<BYTE>(severObj + gameSocketIsEncryption))
		{
			//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket 5\n");
			char* encryptionBuffer = new char[sendBufferLen];
			GameCore_EncryptPacket(severObj + encryptionPack_rcx, sendBufferLen, oldBuf, encryptionBuffer);
			//DEBUG_INFO_OUTPUT("fs:  GameCore_SendPacket 7\n");
			ret = ::send((SOCKET)s, encryptionBuffer, sendBufferLen, 0);
			delete[]encryptionBuffer;
		}
		else
		{
			//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket 6\n");
			ret = ::send((SOCKET)s, oldBuf, sendBufferLen, 0);
		}
		delete[]oldBuf;
		//DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket socket : %llx\n", s);

		return ret;
	}
	else
	{
		DEBUG_INFO_OUTPUT("fs: GameCore_SendPacket invalid socket\n");
		//PrintA("fs:??з?????ЧSOCKET");
	}
	return 0;
}

//?????????
typedef UINT64(__fastcall* fnEncryptPacket)(UINT64 a1, SIZE_T bufLen, const void* bufOld, void* outPutBuf);


UINT64 GameCore_EncryptPacket(UINT64 a1, SIZE_T bufLen, const void* inputBuf, void* outputBuf)
{

	auto CALL = (fnEncryptPacket)(GameCore_GetGameBaseAddress() + encryptionPack_CALL);
	return CALL(a1, bufLen, inputBuf, outputBuf);
}


UINT64 GameCore_SkillGetAttribute(UINT32 attribute)
{

	if (!g_TLSkillFormula)
	{
		return 0;
	}

	UINT64 begin = GameCore_read<UINT64>(g_TLSkillFormula + skillAttributeArray);
	UINT32 size = GameCore_read<UINT32>(g_TLSkillFormula + skillAttributeArray + 0x8);
	if (!begin)
	{
		return 0;
	}
	for (UINT64 i = 0; i < size; i++)
	{
		UINT64 node = begin + i * 0x20;
		if (attribute == GameCore_read<UINT32>(node))
		{
			return  GameCore_read<UINT64>(node + 0x8);
		}
	}
	return UINT64();
}

typedef UINT64(__fastcall* SWidgetGetSubObjSize_FUN)(UINT64);

UINT32 GameCore_SWidgetGetSubObjSize(UINT64 obj)
{
	UINT64 vfun = GameCore_read<UINT64, 2>(obj, { 0 , UIBase_OFFSET2 });
	if (!vfun)
	{
		return 0;
	}
	auto CALL = (SWidgetGetSubObjSize_FUN)(vfun);
	UINT64 UIObjManage = CALL(obj);
	if (!UIObjManage)
	{
		return 0;
	}
	return (*(UINT32(__fastcall**)(UINT64))(*(UINT64*)UIObjManage))(UIObjManage);
}

//?????????SWidget?????
typedef void(__fastcall* SWidgetGetSubObj_FUN)(UINT64, char*, UINT64);



void GameCore_SWidgetGetSubObj(UINT64 obj, UINT64* output, UINT32 i)
{
	UINT64 vfun = GameCore_read<UINT64, 2>(obj, { 0 , UIBase_OFFSET2 });
	if (!vfun)
	{
		return;
	}
	auto CALL = (SWidgetGetSubObjSize_FUN)(vfun);
	UINT64 UIObjManage = CALL(obj);
	if (!UIObjManage)
	{
		return;
	}
	(*(void(__fastcall**)(UINT64, char*, UINT64))(*(UINT64*)UIObjManage + 0x10))(UIObjManage, (char*)output, i);
}

void GameCore_EnumSWidgetsInternal(UINT64 widget, CEnumSWidgetsContext* context)
{
	if (context->stopped)
		return;

	std::wstring text;
	std::string typeName;

	GameCore_GetNameUE(GameCore_read<UINT32>(widget + 0x248), typeName);

	{
		//?ui???.
		auto hashedTypeName = typeName;

		if ("STextBlockTL" == hashedTypeName)
		{
			GameCore_UEGetText(GameCore_read<UINT64>(widget + 0x268), text);
		}
		else if ("SRichTextBlock" == hashedTypeName || "STextBlock" == hashedTypeName)
		{
			GameCore_UEGetText(GameCore_read<UINT64>(widget + 0x258), text);
		}
		else if ("SInvalidationPanel" == hashedTypeName)
		{
			//DEBUG_INFO_OUTPUT("fs: GameCore_SInvalidationPanelRecursion  11");
			GameCore_SInvalidationPanelRecursion(widget, context);
			//DEBUG_INFO_OUTPUT("fs: GameCore_SInvalidationPanelRecursion  22");
			//DEBUG_INFO_OUTPUT("fs:GameCore_SInvalidationPanelRecursion:%llx\n", widget);
		}
	}

	bool bStop = context->callback(widget, text);
	//DEBUG_INFO_OUTPUT("fs: GameCore_SWidgetGetSubObjSize  11");
	UINT32 size = GameCore_SWidgetGetSubObjSize(widget);
	//DEBUG_INFO_OUTPUT("fs: GameCore_SWidgetGetSubObjSize  22");
	//DEBUG_INFO_OUTPUT("fs:GameCore_EnumSWidgetsInternal size:%d\n", size);

	for (UINT32 i = 0; i < size; i++)
	{
		//DEBUG_INFO_OUTPUT("fs:GameCore_EnumSWidgetsInternal : %d\n", i);
		UINT64 output[4] = { 0 };

		//DEBUG_INFO_OUTPUT("fs: GameCore_SWidgetGetSubObj  11");
		GameCore_SWidgetGetSubObj(widget, output, i);
		//DEBUG_INFO_OUTPUT("fs: GameCore_SWidgetGetSubObj  22");
		UINT64 subObj = output[0];
		UINT64 temp = output[1];

		if (subObj)
		{

			if (GameCore_read<char>(subObj + UIOBJ_isVisual) != 2)
			{
				//???
				context->subctx.emplace_back(subObj);
			}
		}

		//??????????????????????????getSubObj?л????+1 , ????????????
		if (temp)
		{
			context->freectx.emplace_back(temp);
			//???????????ü???????????GameCore_EnumSWidgets?????????????????б??????
#if 0
			int index = GameCore_read<int>(temp + 0x8);
			DEBUG_INFO_OUTPUT("fs:widget:%llx  temp: %llx index:%d typename:%s\n", subObj, temp, index, typeName.c_str());
			index--;
			DEBUG_INFO_OUTPUT("fs:index  %d\n", index);
			GameCore_write<int>(temp + 0x8, index);
#endif
		}
	}

	if (bStop)
	{
		context->stopped = true;
	}
}

void GameCore_EnumSWidgets(UINT64 widget, const std::function<bool(UINT64 obj, const std::wstring& text)>& callback)
{
	CEnumSWidgetsContext ctx;

	ctx.callback = callback;

	ctx.subctx.emplace_back(widget);

	while (ctx.subctx.size())
	{
		//DEBUG_INFO_OUTPUT("fs:GameCore_EnumSWidgets ctx.subctx.size() %d\n", ctx.subctx.size());
		auto subctx = ctx.subctx[ctx.subctx.size() - 1];

		ctx.subctx.pop_back();
		if (subctx)
		{
			GameCore_EnumSWidgetsInternal(subctx, &ctx);
		}

		if (ctx.stopped)
			break;

		if (ctx.subctx.empty())
			break;
	}

	//??????????ü???
	for (const auto& temp : ctx.freectx)
	{
		int index = GameCore_read<int>(temp + 0x8);
		index--;
		GameCore_write<int>(temp + 0x8, index);
	}
}

UINT64 GameCore_SWidgetGetRoot()
{
	return  GameCore_read<UINT64, 3>(GameCore_GetGameBaseAddress() + UIBase, { 0 , UIBase_OFFSET1 , 0 });
}

void GameCore_SWidgetGetRect(UINT64 widget, SWidget& rect)
{
	if (IsReadPtr(widget))
	{
		rect.x = GameCore_read<float>(widget + 0xdc);
		rect.y = GameCore_read<float>(widget + 0xdc + 0x4);
		rect.width = GameCore_read<float>(widget + 0xd0);
		rect.height = GameCore_read<float>(widget + 0xd4);
	}
}

//
typedef void(__fastcall* GetSubObjSize_SInvalidationPanel_FUN)(UINT64, char*, UINT64);


UINT64 GetSubObjSize_SInvalidationPanel(UINT64 obj)
{
	if (!IsReadPtr(obj))
	{
		return 0;
	}
	auto UIObjManage = obj + 0x258;

	return (**(__int64(__fastcall***)(__int64))UIObjManage)(UIObjManage);
}


//
typedef void(__fastcall* GetSubObj_SInvalidationPanel_FUN)(UINT64, char*, UINT64);

void GetSubObj_SInvalidationPanel(DWORD64 obj, UINT64* output, UINT32 i)
{
	if (!IsReadPtr(obj))
	{
		return;
	}
	auto UIObjManage = obj + 0x258;
	(*(void(__fastcall**)(UINT64, char*, UINT64))(*(UINT64*)UIObjManage + 0x10))(UIObjManage, (char*)output, i);
}

void GameCore_SInvalidationPanelRecursion(DWORD64 widget, CEnumSWidgetsContext* context)
{
	if (context->stopped)
		return;

	UINT64 num = GetSubObjSize_SInvalidationPanel(widget);

	for (size_t i = 0; i < num; i++)
	{
		UINT64 output[4]{ 0 };
		GetSubObj_SInvalidationPanel(widget, output, i);

		if (IsReadPtr(output[0]))
		{

			if (GameCore_read<LONG>(output[0] + UIOBJ_isVisual) != 2)
			{
				//GameCore_SWidgetFind(output[0], start , func);
				context->subctx.emplace_back(output[0]);
			}
		}

		if (IsReadPtr(output[1]))
		{

			//???????????????????????ü?????????????????б????
			//int index = GameCore_read<int>(output[1] + 0x8);
			//index--;
			//GameCore_write<int>(output[1] + 0x8, index);
			context->freectx.emplace_back(output[1]);
		}
	}
}

//---------------------------------------------------------------------------------------- ????? ----------------------------------------------------------------------------------------

//
typedef bool(__fastcall* IsTeleportPointOpenFun)(UINT64 TLTerritoryFog, UINT64 id);

bool IsTeleportPointOpen(DWORD64 id)
{
	if (!g_TLTerritoryFog)
	{
		return false;
	}

	auto CALL = (IsTeleportPointOpenFun)(GameCore_GetGameBaseAddress() + fs_IsTeleportPointOpen_CALL);
	return CALL(g_TLTerritoryFog, id);

}

//---------------------------------------------------------------------------------------- ????? ----------------------------------------------------------------------------------------

//
typedef UINT64(__fastcall* SkillID1ToAttributeFUN)(UINT64 TLSkillSet, void* output, UINT32 id);

UINT64 SkillID1ToAttribute(UINT32 id)
{
	if (!g_TLSkillSet)
	{
		return 0;
	}

	auto CALL = (SkillID1ToAttributeFUN)(GameCore_GetGameBaseAddress() + fs_SkillID1ToAttribute_CALL);
	UINT64 output[4] = { 0 };
	auto ret = CALL(g_TLSkillSet, (char*)output, id);
	UINT64 sharedPtr = output[1];
	if (sharedPtr)
	{
		(*(UINT32*)(sharedPtr + 0x8))--;
	}
	return output[0];
}


//---------------------------------------------------------------------------------------- ????? ----------------------------------------------------------------------------------------

//
typedef UINT64(__fastcall* GetSkillLevelFUN)(UINT64 AttributeObj);

UINT64 GetSkillLevel(UINT64 AttributeObj)
{
	if (!IsReadPtr(AttributeObj))
	{
		return 0;
	}
	auto CALL = (GetSkillLevelFUN)(GameCore_GetGameBaseAddress() + fs_GetSkillLevel_CALL);
	auto result = CALL(AttributeObj);

	return result;
}

typedef UINT64* (__fastcall* getCurrency_fun)(UINT64 TLInventory, unsigned __int8* type);

UINT64 GetCurrency(UINT8 type)
{
	auto CALL = (getCurrency_fun)(GameCore_GetGameBaseAddress() + getCurrency_CALL);
	UINT8 type_ = type;
	auto result = CALL(g_TLInventory, &type_);
	if (result)
	{
		return *result;
	}
	return 0;
}

typedef UINT64* (__fastcall* GetScheduleInfo_fun)(UINT64 TLTableMaster, UINT64* output, UINT64 id);

UINT64 GetScheduleInfo(UINT64 id)
{
	auto CALL = (GetScheduleInfo_fun)(GameCore_GetGameBaseAddress() + GetScheduleInfoCall);
	auto TLTableMaster = GameCore_read<UINT64>(g_TLTableMaster + ScheduleCallRcx);
	if (TLTableMaster)
	{
		UINT64  output[2] = { 0 };
		auto result = CALL(TLTableMaster, output, id);
		return output[0];
	}
	
	return 0;
}


typedef UINT8(__fastcall* GameCore_Interactive_fun)(UINT64 rcx, UINT64 rdx, char* acotr_id);

UINT64 GameCore_Interactive(int acotr_id)
{
	if (!g_TLMyPc)
	{
		return 0;
	}
	auto CALL = (GameCore_Interactive_fun)(GameCore_GetGameBaseAddress() + Interactive_CALL);
	auto rcx = g_TLMyPc + fs_movToPoint_rcx;
	auto rdx = GameCore_read<UINT64>(g_TLMyPc + fs_movToPoint_rcx + 0x10);
	if (!rdx)
	{
		return 0;
	}
	char p[0x20] = { 0 };
	*((int*)(p + 0x18)) = acotr_id;
	auto result = CALL(rcx, rdx, p);
	return result;
}

typedef bool(__fastcall* GameCore_MovToActor_fun)(UINT64 TLMyPc, int type, int actor_id);

bool GameCore_MovToActor(int actor_id, int type)
{
	if (!g_TLMyPc)
	{
		return false;
	}
	auto CALL = (GameCore_MovToActor_fun)(GameCore_GetGameBaseAddress() + fs_movToActor);
	auto result = CALL(g_TLMyPc, type, actor_id);

	return result;
}

size_t GameCore_GetGameBaseAddress()
{
	static size_t ImageBase = 0;
	if (ImageBase == 0)
	{
		//PPEB peb = (PPEB)__readgsqword(0x60);
		//ImageBase = (size_t)peb->Reserved3[1];
		ImageBase = (UINT64)GetModuleHandleA(skCrypt("tl.exe"));
	}
	return ImageBase;
}

bool IsReadPtr(UINT64 add)
{
	if (!IsBadReadPtr((const void*)(add), 8))
	{
		return true;
	}
	return false;
}

//void DEBUG_INFO_OUTPUT(const char* fmt, ...)
//{
//
//	// ????????????????????洢?????????????  
//	// ???????????????????????????С  
//	const size_t bufferSize = 1024 * 4;
//	char buffer[bufferSize];
//
//
//	// ?????va_list  
//	va_list args;
//	va_start(args, fmt);
//
//
//	// ???vsnprintf???????????????д??????  
//	// ??????????bufferSize - 1?????????????????????????????λ???'\0'  
//	vsnprintf(buffer, bufferSize - 1, fmt, args);
//
//
//	// ????va_list?????  
//	va_end(args);
//
//	OutputDebugStringA(buffer);
//	// ?????????е??????????std::string??????  
//}

//void DEBUG_INFO_OUTPUTW(const wchar_t* fmt, ...)
//{
//	const size_t bufferSize = 1024 * 4;
//	wchar_t buffer[bufferSize];
//
//	va_list args;
//	va_start(args, fmt);
//
//	 使用 _vsnwprintf 代替 vsnwprintf  
//	_vsnwprintf_s(buffer, bufferSize, bufferSize - 1, fmt, args);
//
//	va_end(args);
//
//	OutputDebugStringW(buffer);
//}


void UtilUnicodeToUTF8(const std::wstring& unicodeStr, std::string& outUtf8Str) {
	// 首先检查输入字符串是否为空  
	if (unicodeStr.empty()) {
		outUtf8Str.clear();
		return;
	}

	// 计算需要的缓冲区大小（包括null终止符）  
	int utf8Len = WideCharToMultiByte(CP_UTF8, 0, unicodeStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
	if (utf8Len == 0) {
		// 转换失败，抛出异常或处理错误  
		throw std::runtime_error("WideCharToMultiByte failed to calculate buffer size.");
	}

	// 为UTF-8字符串分配足够的空间（不包括null终止符，因为std::string会自动添加）  
	outUtf8Str.resize(utf8Len - 1);

	// 执行转换  
	int bytesWritten = WideCharToMultiByte(CP_UTF8, 0, unicodeStr.c_str(), -1, &outUtf8Str[0], utf8Len, nullptr, nullptr);
	if (bytesWritten == 0) {
		// 转换失败，抛出异常或处理错误  
		throw std::runtime_error("WideCharToMultiByte failed to convert string.");
	}

	// 确保转换后的字符串大小正确（不包括自动添加的null终止符）  
	outUtf8Str.resize(bytesWritten - 1);

	// 注意：std::string在resize时会自动添加null终止符，所以我们不需要手动添加  
}

void GameCore_GetAttackInfo(size_t m_obj, const std::map<int, float>& m_skillAttackSpeed, SAttackInfo& attackInfo)
{
	UINT64 temp = GameCore_read<UINT64>(m_obj + monster_skill_release_1);
	if (!temp)
	{
		return;
	}

	UINT64 begin = GameCore_read<UINT64>(temp + monster_skill_release_2);
	UINT32 size = GameCore_read<UINT32>(temp + monster_skill_release_2 + 0x8);
	if (!begin || size > 0xff)
	{
		return;
	}

	for (UINT32 i = 0; i < size; i++)
	{
		UINT64 node = begin + i * 0x20;
		UINT64 attackInfoPtr = GameCore_read<UINT64>(node + 0x8);
		if (attackInfoPtr)
		{
			double castTime = GameCore_read<double>(attackInfoPtr + 0x8);
			UINT32 targetID = GameCore_read<UINT32>(attackInfoPtr + 0x20);
			UINT64 skillInfo = GameCore_read<UINT64>(attackInfoPtr + 0x18);
			int skillID2 = GameCore_read<int>(skillInfo + 0x10);
			if (skillInfo)
			{
				//PrintA("fs: castID:%x  %x" , m_castID , skillID2);
				//PrintA("fs: -----------skillInfo:%p castID:%x  %x", skillInfo , m_castID, skillID2);
				auto skillAttackSpeed = m_skillAttackSpeed.find(skillID2);
				if (skillAttackSpeed == m_skillAttackSpeed.end())
				{
					break;
				}
				//DEBUG_INFO_OUTPUT("fs: skillInfo %p\n", skillInfo);
				float chargingTime = GameCore_read<float>(skillInfo + RemainingTimeSkills) * skillAttackSpeed->second;


				LARGE_INTEGER start{};
				QueryPerformanceCounter(&start);
				double curTime = (double)start.QuadPart * 0.0000001 + 16777216.0;
				double 技能触发剩余时间 = (castTime + chargingTime) - curTime;

				if (技能触发剩余时间 > 0.001)
				{
					//DEBUG_INFO_OUTPUT("fs: skillInfo:%llx \n" , skillInfo);

					attackInfo.m_skillChargeRemainingTime = 技能触发剩余时间;
					attackInfo.m_skillTargetID = targetID;
					//attackInfo.m_castTime = castTime;
					//attackInfo.m_chargingTime = chargingTime;

					UINT32 nameID = GameCore_read<UINT32, 2>(attackInfoPtr, { 0x18 , 0x8 });

					//DEBUG_INFO_OUTPUT("fs: attackInfoPtr %p  nameID:%x \n", attackInfoPtr , nameID);

					if (nameID)
					{
						GameCore_GetNameUE(nameID, attackInfo.m_skillName);
					}
					return;
				}
			}
		}
	}

}

bool GameCore_IsPlayer(UINT64 obj)
{
	if (!IsReadPtr(obj))
	{
		return false;
	}
	auto ret = (*(UINT64(__fastcall**)(UINT64))(*(UINT64*)(obj) + 0xB8i64))(obj);
	if (ret)
	{
		return true;
	}
	return false;
}

#define M_PI 3.14159265358979323846  // 更精确的π值

// 封装函数，计算人物面向怪物的横向和纵向角度
void CalculateFacingAngles(float cameraX, float cameraY, float cameraZ,
	float monsterX, float monsterY, float monsterZ,
	float horizontalAngle, float verticalAngle,
	float& outYaw, float& outPitch)
{
	// 计算目标怪物相对于人物相机的方向向量
	float directionX = monsterX - cameraX;
	float directionY = monsterY - cameraY;
	float directionZ = monsterZ - cameraZ;

	// 使用反三角函数计算横向和纵向角度
	outYaw = atan2(directionY, directionX) * 180.0 / M_PI;
	outPitch = atan2(directionZ, sqrt(directionX * directionX + directionY * directionY)) * 180.0 / M_PI;

	// 调整角度范围到 -180 到 180 和 50 到 -80
	outYaw = fmod(outYaw - horizontalAngle, 360.0);
	outPitch = fmod(outPitch - verticalAngle, 360.0);

	if (outYaw < -180.0) {
		outYaw += 360.0;
	}
	else if (outYaw > 180.0) {
		outYaw -= 360.0;
	}

	if (outPitch > 50.0) {
		outPitch = 50.0;
	}
	else if (outPitch < -80.0) {
		outPitch = -80.0;
	}
}



const float epsilon = 1e-6; // 定义一个小的容差值  
void GameCore_FacingCoordinates(CActorSharedPtr LocalPlayer , const TLPoint& p)
{
	if (!g_SpringArmComp)
		return;

	if (!LocalPlayer)
		return;


	TLPoint target = p;
	GameCore_PointRToV(&target);
	float horizontalAngle = 0, verticalAngle = 0;

	// 调用函数并获取横向和纵向角度  
	float yaw, pitch;
	CalculateFacingAngles(LocalPlayer->m_vx, LocalPlayer->m_vy, LocalPlayer->m_vz,
		target.x, target.y, target.z,
		horizontalAngle, verticalAngle,
		yaw, pitch);



	// 更新朝向  
	GameCore_write<float>(g_SpringArmComp + cameraXY, pitch);
	GameCore_write<float>(g_SpringArmComp + cameraXY + 0x4, yaw);
}


SIZE_T GameCore_GetPeSize(HMODULE hModule) {
	// 获取 DOS 头
	PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule;
	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
		return 0; // 不是有效的 PE 文件
	}

	// 获取 PE 头
	PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((BYTE*)pDosHeader + pDosHeader->e_lfanew);
	if (pNtHeaders->Signature != IMAGE_NT_SIGNATURE) {
		return 0; // 不是有效的 NT 头
	}

	// 获取节表
	PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION(pNtHeaders);
	SIZE_T totalSize = 0;

	for (int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++) {
		totalSize += pSectionHeader[i].SizeOfRawData;
	}

	return totalSize;
}

#include "UseEquipment.pb-c.h"
void ScriptAPI_UseEquipment(UINT64 id, UINT32 index)
{
	IM__PUseEquipment useEquipment;
	im__puse_equipment__init(&useEquipment);
	useEquipment.id = id;
	useEquipment.index = index;
	size_t packed_size = protobuf_c_message_get_packed_size((const ProtobufCMessage*)&useEquipment);
	if (packed_size)
	{
		std::shared_ptr<uint8_t[]> packedBuf(new uint8_t[packed_size], std::default_delete<uint8_t[]>());
		if (packedBuf)
		{
			im__puse_equipment__pack(&useEquipment, packedBuf.get());
			GameCore_SendPacket(0x2804, packedBuf.get(), packed_size);
		}
	}
}

bool ScriptAPI_FindSWidget(const std::string& text_, OUT SWidget& rect)
{
	bool bFound = false;
	std::wstring wText;
	UtilUTF8ToUnicode(text_, wText);

	GameCore_EnumSWidgets(GameCore_SWidgetGetRoot(), [&wText, &rect, &bFound](UINT64 obj, const std::wstring& text) {
		//DEBUG_INFO_OUTPUTW(L"fs: text:%s  wText:%s  %d %d %d" , text.c_str() , wText.c_str()  , text.size() , wText.size() ,  text.find(wText));

		if (text.find(wText) != std::wstring::npos)
		{
			bFound = true;

			DEBUG_INFO_OUTPUTW(L"fs:GameCore_SWidgetFind() ->  widget:%llx  rect:%d , %d , %d , %d  text:%s \n", obj, (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, text.c_str());

			GameCore_SWidgetGetRect(obj, rect);
			return true;//返回值含义修改为true停止枚举
		}

		return false;
		});

	return bFound;
}
char* byteArrayToHexString(const unsigned char* byteArray, size_t len) {
	// 每个字节将转换为两个十六进制字符，因此字符串长度是字节数组长度的两倍
	size_t hexStrLen = len * 2 + 1; // +1 是为了存放字符串结束符 '\0'
	char* hexStr = (char*)malloc(hexStrLen);

	if (!hexStr) {
		// 如果内存分配失败，返回 NULL
		return NULL;
	}

	// 将字节数组转换为十六进制字符串
	for (size_t i = 0; i < len; ++i) {
		// 使用 snprintf 安全地格式化字符串
		snprintf(hexStr + i * 2, 3, "%02x", byteArray[i]); // 3 是为了包括结束符
	}

	// hexStr 已经以 '\0' 结束，无需手动添加
	return hexStr;
}
#include "useConsumable.pb-c.h"
void ScriptAPI_UseConsumable(CActorSharedPtr m_LocalPlayerActor , UINT64 itemID, int itemID2, int destID, float destX, float destY, float destZ)
{
	DEBUG_INFO_OUTPUT("fs:ScriptAPI_ItemUsage");
	IM__PUseConsumable item;
	im__puse_consumable__init(&item);
	item.toward = 0;
	item.itemid2 = itemID2;
	item.u = 1;
	IM__PUseConsumable__Pv itemPV = IM__PUSE_CONSUMABLE__PV__INIT;
	item.item = &itemPV;
	itemPV.itemid = itemID;
	item.destid = destID;
	UINT32 count = GameCore_read<UINT32>(g_TLMyPc + skillMessageCount);
	count++;
	GameCore_write<UINT32>(g_TLMyPc + skillMessageCount, count);
	item.count = count;
	IM__PUseConsumable__PPoint destPoint = IM__PUSE_CONSUMABLE__PPOINT__INIT;
	IM__PUseConsumable__PPoint selfPoint = IM__PUSE_CONSUMABLE__PPOINT__INIT;
	destPoint.x = destX;
	destPoint.y = destY;
	destPoint.z = destZ;
	selfPoint.x = m_LocalPlayerActor->m_x;
	selfPoint.y = m_LocalPlayerActor->m_y;
	selfPoint.z = m_LocalPlayerActor->m_z;
	item.destpoint = &destPoint;
	item.selfpoint = &selfPoint;

	size_t packed_size = protobuf_c_message_get_packed_size((const ProtobufCMessage*)&item);
	if (packed_size)
	{
		std::shared_ptr<uint8_t[]> packedBuf(new uint8_t[packed_size], std::default_delete<uint8_t[]>());
		if (packedBuf)
		{
			im__puse_consumable__pack(&item, packedBuf.get());
			std::string str = "fs:";
			str += byteArrayToHexString(packedBuf.get(), packed_size);
			DEBUG_INFO_OUTPUT(str.c_str());
			GameCore_SendPacket(0x120B, packedBuf.get(), packed_size);
		}
	}
}

#include "useConsumableWithQuantity.pb-c.h"
void ScriptAPI_useConsumableWithQuantity(UINT64 itemID, int sum)
{
	IM__PUseConsumableWithQuantity item;
	im__puse_consumable_with_quantity__init(&item);
	item.itemid = itemID;
	item.sum = sum;

	size_t packed_size = protobuf_c_message_get_packed_size((const ProtobufCMessage*)&item);
	if (packed_size)
	{
		std::shared_ptr<uint8_t[]> packedBuf(new uint8_t[packed_size], std::default_delete<uint8_t[]>());
		if (packedBuf)
		{
			im__puse_consumable_with_quantity__pack(&item, packedBuf.get());
			std::string str = "fs:";
			str += byteArrayToHexString(packedBuf.get(), packed_size);
			DEBUG_INFO_OUTPUT(str.c_str());
			GameCore_SendPacket(0x2850, packedBuf.get(), packed_size);
		}
	}
}
#include "interactive.pb-c.h"
void ScriptAPI_Interactive(UINT64 acotr_id, UINT64 type)
{
	IM__PInteractive PInteractive;
	im__pinteractive__init(&PInteractive);
	PInteractive.id = acotr_id;

	//
	short pack_id = 0x2702;
	if (type == 1)
	{
		pack_id = 0x270b;
	}
	size_t packed_size = protobuf_c_message_get_packed_size((const ProtobufCMessage*)&PInteractive);
	if (packed_size)
	{
		std::shared_ptr<uint8_t[]> packedBuf(new uint8_t[packed_size], std::default_delete<uint8_t[]>());
		if (packedBuf)
		{
			im__pinteractive__pack(&PInteractive, packedBuf.get());
			std::string str = "fs:";
			str += byteArrayToHexString(packedBuf.get(), packed_size);
			DEBUG_INFO_OUTPUT(str.c_str());
			//270b
			GameCore_SendPacket(pack_id, packedBuf.get(), packed_size);
		}
	}
}

#include "setCharacterName.pb-c.h"
void ScriptAPI_SetCharacterName(std::string name)
{
	IM__PSetCharacterName SetCharacterName;
	im__pset_character_name__init(&SetCharacterName);
	SetCharacterName.name = (char*)(name.c_str());

	size_t packed_size = protobuf_c_message_get_packed_size((const ProtobufCMessage*)&SetCharacterName);
	if (packed_size)
	{
		std::shared_ptr<uint8_t[]> packedBuf(new uint8_t[packed_size], std::default_delete<uint8_t[]>());
		if (packedBuf)
		{
			im__pset_character_name__pack(&SetCharacterName, packedBuf.get());
			GameCore_SendPacket(0x290e, packedBuf.get(), packed_size);
		}
	}
}
//获取 计算距离所需参数
typedef float(__fastcall* fnGetObjectDistance)(UINT64 actorObj);
float GameCore_GetObjectDistance(const CActor* actor1, const CActor* actor2)
{
	if (!IsReadPtr(actor2->m_obj))
	{
		return 0;
	}
	auto vftable = *(UINT64**)(actor2->m_obj);
	auto vfunc = (fnGetObjectDistance)vftable[calculate_distance / 8];
	auto v10 = vfunc(actor2->m_obj);
	if (v10 == 0)
	{
		return 0;
	}

	float v9 = sqrt((actor2->m_vy - actor1->m_vy) * (actor2->m_vy - actor1->m_vy) + (actor2->m_vx - actor1->m_vx) * (actor2->m_vx - actor1->m_vx));
	v9 = fmaxf(v9 - v10, 0);

	return v9 / 100;
}

void GameCore_MoveTo(float x, float y, float z)
{
	if (!g_TLMyPc)
	{
		return;
	}
	TLPoint r(x , y , z);
	GameCore_PointRToV(&r);
	GameCore_write<UINT64>(g_TLMyPc + destPoint_OFF + 0x68, 0x0000000000000001);
	//GameCore_write<UINT64>(g_TLMyPc + 目的地坐标偏移 + 0x70, 0xFFFFFFFF00000001);
	GameCore_write<float>(g_TLMyPc + destPoint_OFF + 0x78 , r.x);
	GameCore_write<float>(g_TLMyPc + destPoint_OFF + 0x7c, r.y);
	GameCore_write<float>(g_TLMyPc + destPoint_OFF + 0x80, r.z);
}
typedef __int64(__fastcall* fs_ToggleKeepMoveForward_fun)(__int64 a1);
void GameCore_ToggleKeepMoveForward()
{	
	if (!g_TLGameModeController)
	{
		return;
	}
	auto call = (fs_ToggleKeepMoveForward_fun)(GameCore_GetGameBaseAddress() + fs_ToggleKeepMoveForward_CALL);
	call(g_TLGameModeController);
}

void GameCore_MouseClick(int hwnd, int x, int y , int mode)
{
	GameCore_write<char>(GameCore_read<UINT64>(GameCore_GetGameBaseAddress() + UIBase) + UIFocus, 1);
	// 发送 WM_LBUTTONDOWN 消息
	// 发送 WM_LBUTTONDOWN 消息
	if (mode == 1)
	{
		PostMessage((HWND)hwnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(x, y));
	}
	else if (mode == 2) // 添加左键抬起操作
	{
		PostMessage((HWND)hwnd, WM_LBUTTONUP, 0, MAKELPARAM(x, y));
	}
	else if (mode == 3) // 添加右键按下操作
	{
		PostMessage((HWND)hwnd, WM_RBUTTONDOWN, MK_RBUTTON, MAKELPARAM(x, y));
	}
	else if (mode == 4) // 添加右键抬起操作
	{
		PostMessage((HWND)hwnd, WM_RBUTTONUP, 0, MAKELPARAM(x, y));
	}
}

void GameCore_ExecuteKeyPress(int hwnd, UINT keyCode, int mode)
{
	GameCore_write<char>(GameCore_read<UINT64>(GameCore_GetGameBaseAddress() + UIBase) + UIFocus, 1);
	// 根据模式设置消息类型
	UINT msg = (mode == 1) ? WM_KEYDOWN : WM_KEYUP;

	// 创建虚拟键消息
	PostMessage((HWND)hwnd, msg, keyCode, 0);
}

typedef UINT64(__fastcall* IDToObj_fun)(UINT64 a1);
UINT64 GameCore_IDToObj(UINT64 id)
{
	IDToObj_fun call = (IDToObj_fun)(GameCore_GetGameBaseAddress() + IDToObj_CALL);
	return call(id);
}

size_t GameCore_PartyGetStructById(size_t ID)
{
	if (!g_TLMapIcon)
		return NULL;
	auto CALL = (size_t (__fastcall*)(size_t TLMapIcon, size_t ID))(GameCore_GetGameBaseAddress() + 0x1C3EA00);
	return CALL(g_TLMapIcon, ID);
}

bool GameCore_IsDungeon()
{
	if (!g_TLTableMaster)
		return false;
	if (!g_TLMap)
		return false;

	size_t output{};
	(*(void(__fastcall**)(size_t, size_t*, size_t))(*(size_t*)(*(size_t*)(g_TLTableMaster + IsDungeon_OFF1) + IsDungeon_OFF2) + 0x30))(
		*(size_t*)(g_TLTableMaster + IsDungeon_OFF1) + IsDungeon_OFF2,
		&output,
		*(unsigned int*)(g_TLMap + Dungeon_ID));

	if (output)
	{
		if (GameCore_read<char>(output + 0x28) != 1)
		{
			return true;
		}
	}
	return false;
}


